#Calculating a numbers sign
def sign(x):
    if x < 0:
        return -1
    elif x > 0:
        return 1
    return 0

sign(5)
sign(-5)
sign(0)

#A more elegant solution would be to exploit an interesting behaviour of the bool type, False - False
False - True
True - False
True - True 

def sign(x):
    return (x > 0) - (x < 0)

sign(-5)
sign(5)
sign(0)

#Computing a determinant
#det = (qx - px)(ry - py) - (qy - py)(rx - px)
def orientation(p, q, r): 
    d = (q[0] - p[0]) * (r[1] - p[1]) - (q[1] - p[1]) * (r[0] - p[0]) 
    return sign(d)

a = (0, 0)
b = (4, 0)
c = (4, 3)
orientation(a, b, c)
orientation(a, c, b)

d = (8, 6)
orientation(a, c, d) 


#Using float for computational geometry
e = (0.5, 0.5)
f = (12.0, 12.0)
g = (24.0, 24.0)
orientation(e, f, g)

e = (0.5, 0.5000000000000018)
orientation(e, f, g) #Not colinear (as expected)
e = (0.5, 0.5000000000000019) 
orientation(e, f, g) #Is colinear - WTF?
e = (0.5, 0.5000000000000044)
orientation(e, f, g) #Is still colinear - WTF?
e = (0.5, 0.5000000000000046)
orientation(e, f, g) #Finally not colinear anymore


#Analyzing the shortcomings of float
#run code in collinear.py
#fix code to use Fraction instead of float (save it as collinear_using_fractions) and rerun it.
p = (Fraction(p[0]), Fraction(p[1]))
q = (Fraction(q[0]), Fraction(q[1]))
r = (Fraction(r[0]), Fraction(r[1]))

#Representing rounding issues graphically
#Add the approproriate code to collinear and run
import bmp
color = {-1: 0, 0: 127, +1: 255}
pixels = [[color[orientation((px, py), q, r)] for px in pys] for py in reversed(pys)]
bmp.write_grayscale('above_below.bmp', pixels)
#Add the code to collinear_using_fractions and run this.
